#!/usr/bin/perl

######################################################################
package Swignition::RDFModel::Subject;
######################################################################

use XML::LibXML qw(:all);
use strict;

sub new
{
	my $class = shift;
	my $uri   = shift;
	my $this  = {
		uri        => $uri
	};
	bless $this;
	$this->addUri($uri);
	$this->{bovvered} = 0;
	return $this;
}

sub equal_to
{
	my $a = shift;
	my $b = shift;
	
	return 1 if ($a->{uri} eq $b->{uri}); # Optimisation
	
	foreach my $aURI (@{$a->uris})
	{
		foreach my $bURI (@{$b->uris})
		{
			return 1 if ($aURI eq $bURI);
		}
	}
	
	return 0;
}

sub merge
{
	my $this = shift;
	my $new  = shift;

	foreach my $prop ( $new->propertiesObjects )
	{
		unless (defined $this->{properties}->{ $prop->uri })
		{
			$this->{properties}->{ $prop->uri } 
				= Swignition::RDFModel::Property->new($prop->namespace, $prop->localname);
		}
		
		foreach my $v (@{$prop->valObjects})
		{
			$this->{properties}->{ $prop->uri }->addVal($v);
		}
	}
	
	if ($new->objects)
	{
		foreach my $obj ( @{ $new->objects } )
		{
			$this->addObject($obj);
		}
	}
	
	foreach my $uri ( @{ $new->uris } )
	{
		$this->addUri($uri);
	}
}

sub uri
{
	my $this = shift;
	return $this->{uri};
}

sub title
{
	my $this = shift;
	my $prop = $this->property('http://purl.org/dc/terms/title');
	if (defined $prop && $prop->nVals && $prop->firstVal->type==0)
	{
		return $prop->firstVal->toString;
	}
	return 'Untitled';
}

sub addUri
{
	my $this = shift;
	my $uri  = shift;
	
	foreach my $existing (@{ $this->{uris} })
	{
		return if ($existing eq $uri);
	}
	
	push @{ $this->{uris} }, $uri;
	
	my $val = Swignition::RDFModel::Value->new($uri, 1);
	$this->addVal('http://www.w3.org/2006/link#uri', $val);
}

sub uris
{
	my $this = shift;
	return $this->{uris};
}

sub properties
{
	my $this = shift;
	my $ns   = shift;
	
	if (!length $ns)
	{
		return keys %{ $this->{properties} };
	}
	
	my @rv;
	foreach my $p ( values %{ $this->{properties} } )
	{
		push @rv, $p->uri if ($p->namespace eq $ns);
	}
	
	return @rv;
}

sub propertiesObjects
{
	my $this = shift;
	my $ns   = shift;
	
	if (!length $ns)
	{
		return values %{ $this->{properties} };
	}
	
	my @rv;
	foreach my $p ( values %{ $this->{properties} } )
	{
		push @rv, $p if ($p->namespace eq $ns);
	}
	
	return @rv;
}

sub property
{
	my $this = shift;
	my $prop = shift;
	my @rv;
	
	my @props = ($prop);
	if ($this->{page})
	{
		my $page = $this->{page};
		foreach my $p (keys %{ $this->{properties} })
		{
			foreach my $src (qw(RDF RDF1))
			{
				if ($page->{$src}->{$p}
					->{properties}->{'http://www.w3.org/2000/01/rdf-schema#subPropertyOf'})
				{
					my @vals = @{ $page->{$src}->{$p}
						->{properties}->{'http://www.w3.org/2000/01/rdf-schema#subPropertyOf'}
						->{'values'} };
					foreach my $v (@vals)
					{
						push @props, $p
							if ($v->type && ($v->toString eq $prop));
					}
				}
			}
		}
	}

	foreach my $p (@props)
	{
		next unless ( $this->{properties}->{$p} );
		foreach my $v (@{ $this->{properties}->{$p}->{'values'} })
		{
			push @rv, $v;
		}
	}
	
	return unless (@rv);
	
	my $r = Swignition::RDFModel::Property->new($prop);
	$r->{'values'} = \@rv;
	
	return $r;
}

sub vals
{
	my $this = shift;
	my $prop = shift;
	
	my $po = $this->property($prop);
	return unless ($po);
	
	return $po->vals;
}

sub firstVal
{
	my $this = shift;
	my $prop = shift;

	return $this->property($prop)->firstVal
		if $this->property($prop);
}

sub addVal
{
	my $this = shift;
	my $prop = shift;
	my $val  = shift;
	
	if (!defined $this->{properties}->{$prop})
	{
		$this->{properties}->{$prop} = Swignition::RDFModel::Property->new($prop);
		$this->{properties}->{$prop}->setSubject($this);
	}
	
	$this->{bovvered} = 1;

	return $this->propertySimple($prop)->addVal($val);
}

sub am_i_bovvered
{
	my $this = shift;
	return $this->{bovvered};
}

sub triples
{
	my $this = shift;
	my $subj = $this->uri;
	my @rv;
	
	foreach my $property ($this->propertiesObjects)
	{
		foreach my $double ($property->doubles)
		{
			my ($prop, $val, $isres) = @{ $double };
			push @rv, [($subj, $prop, $val, $isres)];
		}
	}
	
	return @rv;
}

sub objects
{
	my $this = shift;
	return $this->{objects};
}

sub addObject
{
	my $this = shift;
	my $obj  = shift;
	
	return unless (ref $obj);
	
	if (UNIVERSAL::can($obj, 'uri'))
	{
		my @uris = $obj->uri(1);
		foreach my $u (@uris)
			{ $this->addUri($u); }

		push @{ $this->{objects} },  $obj;
	}
}

sub dom
{
	my $this = shift;
	return $this->{dom};
}

sub setDom
{
	my $this = shift;
	my $dom  = shift;
	
	$this->{dom} = $dom;
}

sub propertySimple
{
	my $this = shift;
	my $prop = shift;
	
	return $this->{properties}->{$prop};
}


1;
